package com.polaris.live.im.manager

import androidx.annotation.MainThread
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.constant.LiveConst
import com.polaris.live.im.db.dao.SessionListEntityDao
import com.polaris.live.im.db.database.AppDatabase
import com.polaris.live.im.db.entity.SessionEntity
import com.polaris.live.im.sfs.SYSTEM_USER_ID
import com.polaris.live.im.sfs.TYPE_MESSAGE_CALL
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.utils.BitwiseUtils
import com.polaris.live.utils.LifecycleListenerDispatcher
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import kotlin.coroutines.CoroutineContext
import kotlin.math.max

/**
 * 管理会话的增删改查
 *
 * @author Created by 半仙 on 2023/8/23/023 11:58
 */
object ImSessionManager {

    private val sessionMutex = Mutex()

    private val sessionChangeDispatcher =
        LifecycleListenerDispatcher<SessionChangeListener>("sessionChangeDispatcher")
    private val sessionStrangerDispatcher =
        LifecycleListenerDispatcher<SessionStrangerListener>("sessionStrangerDispatcher")
    private val sessionDeleteDispatcher =
        LifecycleListenerDispatcher<SessionDeleteListener>("deleteSessionDispatcher")

    private val strangerPageRef = AtomicInteger()

    private val totalUnreadCount = AtomicLong()
    private val totalStrangerUnreadCount = AtomicLong()

    /**
     * 获取当前的总未读数
     */
    fun getTotalUnreadCount() = max(totalUnreadCount.get(), 0)

    /**
     * 获取当前的默认未读数
     */
    fun getStrangerUnreadCount() = max(totalStrangerUnreadCount.get(), 0)

    /**
     * 重置会话信息
     */
    fun reset() {
        totalUnreadCount.set(0)
        totalStrangerUnreadCount.set(0)
    }

    /**
     * 添加未读数监听
     */
    fun observeUnreadCount(owner: LifecycleOwner, l: SessionChangeListener) {
        sessionChangeDispatcher.observe(owner, l)
    }

    /**
     * 添加陌生人状态变化监听
     */
    fun observeStranger(
        owner: LifecycleOwner,
        isStrangerPage: Boolean,
        l: SessionStrangerListener
    ) {
        if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            return
        }

        if (isStrangerPage) {
            strangerPageRef.incrementAndGet()

            owner.lifecycle.addObserver(object : LifecycleEventObserver {
                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        strangerPageRef.decrementAndGet()
                    }
                }
            })
        }

        sessionStrangerDispatcher.observe(owner, l)
    }

    /**
     * 添加会话删除监听
     */
    fun observeDelete(owner: LifecycleOwner, l: SessionDeleteListener) {
        sessionDeleteDispatcher.observe(owner, l)
    }

    private object Session : CoroutineContext.Element {

        override val key = object : CoroutineContext.Key<Session> {}
    }

    /**
     * 运行在会话
     */
    fun launchSession(block: suspend () -> Unit) {
        CoroutineScopeManager.defaultScope.launch {
            withSession(block)
        }
    }

    /**
     * 运行在会话
     */
    suspend fun <T> withSession(block: suspend () -> T): T = coroutineScope {
        if (coroutineContext[Session.key] != null) {
            block()
        } else {
            withContext(CoroutineScopeManager.defaultDispatcher + Session) {
                sessionMutex.withLock {
                    block()
                }
            }
        }
    }

    //保存消息回话
    internal suspend fun saveSession(
        sessionEntity: SessionEntity,
        isSelfSend: Boolean = false,
        action: (suspend (SessionEntity) -> Unit)? = null
    ) {
        withSession {
            val oldSessionEntity = getSessionDao().getSession(sessionEntity.userId, sessionEntity.otherId)

            val type = sessionEntity.type
            val payload = sessionEntity.payloadBean

            //在聊天的页面里面，不增加
            val newUnreadCount = when {
                isSelfSend || sessionEntity.otherId in ImMessageManager.messageOtherIds -> {
                    0L
                }

                type != null && BitwiseUtils.isBitwise(type, TYPE_MESSAGE_CALL) -> {
                    if (sessionEntity.senderId == UserManager.getUserId()) {
                        0L
                    } else {
                        if (payload?.status == CommonConst.CallType.OVER || payload?.userFrom == LiveConst.SenderFrom.MATCH) {
                            0L
                        } else {
                            1L
                        }
                    }
                }

                else -> {
                    1L
                }
            }

            if (oldSessionEntity == null) {
                sessionEntity.copy(
                    unreadCount = newUnreadCount,
                    strangerUnreadCount = newUnreadCount
                )
            } else {
                //如果是false说明已经操作过了，不需要再次操作
                val isStranger = if (oldSessionEntity.strangerStatus == false) {
                    false
                } else {
                    sessionEntity.strangerStatus
                }
                val isGreetPushMessage = if (sessionEntity.senderId == UserManager.getUserId()) {
                    null
                } else {
                    sessionEntity.greetPushMessage
                }

                oldSessionEntity.copy(
                    command = sessionEntity.command,
                    type = sessionEntity.type,
                    content = sessionEntity.content,
                    senderId = sessionEntity.senderId,
                    timestamp = sessionEntity.timestamp,
                    seqId = sessionEntity.seqId,
                    ext = sessionEntity.ext,
                    payload = sessionEntity.payload,
                    userJson = sessionEntity.userJson,
                    strangerStatus = isStranger,
                    greetPushMessage = isGreetPushMessage,
                    unreadCount = (oldSessionEntity.unreadCount ?: 0) + newUnreadCount,
                    strangerUnreadCount = (oldSessionEntity.strangerUnreadCount ?: 0) + newUnreadCount
                )
            }.apply {
                isTranAcquaintance = oldSessionEntity != null && oldSessionEntity.isStranger() && !isStranger()

                //只有是陌生人并且当前堆栈中没有陌生人列表才增加
                val finalUnread = if (isStranger() && strangerPageRef.get() != 0) {
                    0
                } else {
                    newUnreadCount
                }

                if (finalUnread > 0) {
                    changeUnreadCount(
                        this,
                        finalUnread,
                        if (isStranger() && strangerPageRef.get() == 0 && otherId != SYSTEM_USER_ID) finalUnread else 0
                    )
                }
                //如果最终未读数小于0，需要将其减去
                else {
                    val thisUnreadCount = unreadCount
                    unreadCount = if (thisUnreadCount != null) {
                        thisUnreadCount - newUnreadCount
                    } else {
                        0
                    }
                }
                getSessionDao().saveSession(this)

                action?.invoke(this)
            }
        }
    }

    /**
     * 触发当前用户的总未读数计算
     */
    fun triggerSessionUnreadCountCalculation() {
        launchSession {
            val unreadCount = getSessionDao().getTotalUnreadCount(UserManager.getUserId()) ?: 0
            val strangerUnreadCount = getSessionDao().getUnreadCountByStranger(UserManager.getUserId()) ?: 0

            totalUnreadCount.set(unreadCount)
            totalStrangerUnreadCount.set(strangerUnreadCount)
            onChangeUnreadCount(null, unreadCount)
        }
    }

    /**
     * 转变打招呼超时消息为陌生人消息
     */
    fun convertGreetMessageTimeoutToStranger() {
        launchSession {
            getSessionDao().updateGreetMessageTimeoutToStranger(UserManager.getUserId())
        }
    }

    /**
     * 清除24小时之前的陌生人会话
     */
    fun clearStrangerSessionFromOneDayAgo() {
        launchSession {
            //获取所有超时的的陌生人信息
            val deleteIds = AppDatabase.instance.sessionListDao()
                .getAllSessionByStrangerAndOneDayAgo(UserManager.getUserId())
            deleteIds.forEach {
                deleteSession(it)
            }
        }
    }

    /**
     * 清除所有的陌生人未读数，单个的
     */
    suspend fun clearStrangerAllUnreadCount() {
        withSession {
            //获取所有的陌生人信息
            val strangerSessionIds = getSessionDao().getAllSessionIdsByStranger(UserManager.getUserId())
            if (strangerSessionIds.isEmpty()) {
                return@withSession
            }

            //清除所有的未读数
            invokeClearUnreadCount(*strangerSessionIds.toLongArray())
        }
    }

    /**
     * 清除所有陌生人的未读数，外面的总数
     */
    fun clearStrangerUnreadCount() {
        launchSession {
            //清除陌生人消息的主未读数
            getSessionDao().clearMainUnreadCountByStranger(UserManager.getUserId())
            totalUnreadCount.addAndGet(-getStrangerUnreadCount())
            totalStrangerUnreadCount.set(0)
            onChangeUnreadCount(null, 0)
        }
    }

    /**
     * 清除某些用户的未读数
     *
     * 用于进入聊天界面后清除未读数
     */
    fun clearUnreadCount(vararg otherIds: Long) {
        launchSession {
            invokeClearUnreadCount(*otherIds)
        }
    }

    private suspend fun invokeClearUnreadCount(vararg otherIds: Long) {
        otherIds.forEach {
            val sessionEntity = getSessionDao().getSession(UserManager.getUserId(), it)
            if (sessionEntity != null) {
                invokeClearUnreadCount(
                    sessionEntity,
                    sessionEntity.unreadCount ?: 0,
                    sessionEntity.isStranger()
                )
            }
        }
    }

    private suspend fun invokeClearUnreadCount(
        sessionEntity: SessionEntity,
        unreadCount: Long,
        isStranger: Boolean
    ) {
        if (isStranger) {
            getSessionDao().updateAllUnreadCountByOtherId(
                UserManager.getUserId(),
                sessionEntity.otherId,
                0,
                0
            )
        } else {
            if (unreadCount > 0) {
                getSessionDao().updateUnreadCountByOtherId(
                    UserManager.getUserId(),
                    sessionEntity.otherId,
                    0
                )
            }
        }
        if (unreadCount > 0) {
            if (isStranger) {
                changeUnreadCount(sessionEntity, -unreadCount, -unreadCount)
            } else {
                changeUnreadCount(sessionEntity, -unreadCount, 0)
            }
        } else if (isStranger) {
            onChangeUnreadCount(sessionEntity, unreadCount)
        }
    }

    /**
     * 将会话切换为陌生人会话
     */
    fun switchToStranger(sessionEntity: SessionEntity) {
        launchSession {
            val strangerUnreadCount = getSessionDao()
                .getUnreadCountByOtherId(
                    UserManager.getUserId(),
                    sessionEntity.otherId
                )?.strangerUnreadCount ?: 0

            getSessionDao().updateSessionToStrangerUserByOtherId(
                UserManager.getUserId(),
                sessionEntity.otherId
            )
            if (strangerUnreadCount > 0) {
                //更新陌生人未读数
                totalStrangerUnreadCount.addAndGet(strangerUnreadCount)

                onChangeUnreadCount(sessionEntity, strangerUnreadCount)
            }

            val newSessionEntity = sessionEntity.copy(
                strangerStatus = true,
            ).apply {
                isTranAcquaintance = true
            }
            onStrangerStatusChange(newSessionEntity)
        }
    }

    /**
     * 删除会话
     */
    suspend fun deleteSession(otherId: Long) {
        withSession {
            val newSessionEntity = getSessionDao().getSession(UserManager.getUserId(), otherId)
            if (newSessionEntity != null) {
                invokeClearUnreadCount(
                    newSessionEntity,
                    newSessionEntity.unreadCount ?: 0,
                    newSessionEntity.isStranger()
                )

                AppDatabase.instance.sessionListDao()
                    .deleteSession(UserManager.getUserId(), otherId)
                AppDatabase.instance.messageDao().deleteByUniqueId(UserManager.getUserId(), otherId)

                onDeleteSession(newSessionEntity)
            }
        }
    }

    /**
     * 获取会话未读数
     */
    suspend fun getSessionUnreadNumber(otherId: Long, seqId: Long): Long {
        val session = getSessionDao().getSession(UserManager.getUserId(), otherId) ?: return 0

        return if (session.seqId == seqId) {
            session.unreadCount ?: 0
        } else {
            (session.unreadCount ?: 0) + 1
        }
    }

    private suspend fun changeUnreadCount(
        sessionEntity: SessionEntity?,
        unreadCount: Long,
        strangerUnreadCount: Long
    ) {
        if (unreadCount == 0L && strangerUnreadCount == 0L) {
            return
        }
        totalUnreadCount.addAndGet(unreadCount)
        totalStrangerUnreadCount.addAndGet(strangerUnreadCount)
        onChangeUnreadCount(sessionEntity, unreadCount)
    }

    private suspend fun onChangeUnreadCount(sessionEntity: SessionEntity?, unreadCount: Long) {
        withContext(SmartFoxManager.noticeDispatcher) {
            sessionChangeDispatcher.listeners.forEach {
                it.onChangeUnreadCount(
                    getTotalUnreadCount(),
                    getStrangerUnreadCount(),
                    sessionEntity,
                    unreadCount
                )
            }
        }
    }

    private suspend fun onStrangerStatusChange(sessionEntity: SessionEntity) {
        withContext(SmartFoxManager.noticeDispatcher) {
            sessionStrangerDispatcher.listeners.forEach {
                it.onStrangerStatusChange(sessionEntity)
            }
        }
    }

    private suspend fun onDeleteSession(sessionEntity: SessionEntity) {
        withContext(SmartFoxManager.noticeDispatcher) {
            sessionDeleteDispatcher.listeners.forEach {
                it.onDeleteSession(sessionEntity)
            }
        }
    }

    private fun getSessionDao(): SessionListEntityDao {
        return AppDatabase.instance.sessionListDao()
    }
}

fun interface SessionChangeListener {

    /**
     * 会话未读数变化
     */
    @MainThread
    fun onChangeUnreadCount(
        totalUnreadCount: Long,
        strangerUnreadCount: Long,
        sessionEntity: SessionEntity?,
        unreadCount: Long
    )

}

fun interface SessionStrangerListener {

    /**
     * 陌生人状态变化
     */
    @MainThread
    fun onStrangerStatusChange(sessionEntity: SessionEntity)

}

fun interface SessionDeleteListener {

    /**
     * 会话清除
     */
    @MainThread
    fun onDeleteSession(sessionEntity: SessionEntity)

}